#!/usr/bin/env python

import sys
import time
import bsddb
import optparse
from random import shuffle
from collections import defaultdict
from ctypes import cdll, Structure, c_double, c_int
from os.path import join, abspath, dirname

from nw_sim_base import ALPHABET, parse_generation

class MKResult(Structure):
    _fields_ = [
        ("ev",  c_double),
        ("sd",  c_double),
    ]

NWMC = cdll.LoadLibrary(abspath(join(dirname(__file__), 'nw_sim_process.so')))
NWMC.run_monte_carlo_c.restype = MKResult


def shuffle_string(s):
    l = list(s)
    shuffle(l)
    return ''.join(l)

def simulate(length, weights, iter_num):    
    assert sum(weights.itervalues()) == 1.0

    seq1 = "";
    seq2 = "";
    
    for c, w in weights.iteritems():
        seq1 += c * (length * w)
        seq2 += c * (length * w)

    res = NWMC.run_monte_carlo_c(seq1, seq2, iter_num)
    print len(seq1), res.ev, res.sd
    

def main_test():
    iter_num = 1000
    step_mult = 1.05
    min_length = 10
    max_length = 10000
    
    seq1 = "";
    seq2 = "";
    
    length = min_length
    while length <= max_length:
        prev_length = len(seq1)
        for c in ALPHABET:
            seq1 += c * ((length-prev_length)/len(ALPHABET))
            seq2 += c * ((length-prev_length)/len(ALPHABET))
            seq1 = shuffle_string(seq1)
            seq2 = shuffle_string(seq2)

        if len(seq1) > prev_length:
            res = NWMC.run_monte_carlo_c(seq1, seq2, iter_num)
            print '%i\t%i\t%8.1f\t%8.1f' % (length, len(seq1), res.ev, res.sd)
        
        length = int(round(length * step_mult))

def main():
    iter_num = 1000
    step_mult = 1.05
    min_length = 10
    max_length = 10000
    MIN_STEP   = 10

    for line in sys.stdin:
        weights1, weights2, db_keys = parse_generation(line.strip('\n'))
        db_keys_str = ' '.join(db_keys)
        
        seq1 = "";
        seq2 = "";
        
        length = min_length
        while length <= max_length:
            prev_length = len(seq1)
            for c in ALPHABET:
                seq1 += c * int(round(((length-prev_length)/MIN_STEP)*MIN_STEP*weights1[c]))
                seq2 += c * int(round(((length-prev_length)/MIN_STEP)*MIN_STEP*weights2[c]))
                seq1 = shuffle_string(seq1)
                seq2 = shuffle_string(seq2)

            assert len(seq1) == len(seq2)

            if len(seq1) > prev_length:
                res = NWMC.run_monte_carlo_c(seq1, seq2, iter_num)
                print '%s\t%i\t%i\t%8.1f\t%8.1f' % (db_keys_str, length, len(seq1), res.ev, res.sd)
            
            length = int(round(length * step_mult))



if __name__ == "__main__":
    import gc
    gc.disable()
    
    if len(sys.argv) > 1 and sys.argv[1] == '-t':
        main_test()
    else:
        main()
    

